
package contention

import (
	"sync"
	"time"
)

// TimeoutDetector 的实现，在 TimeoutDetector 中 最重要的字段是 records
// (map[uint64]time.Time 类型） ， 在该 map 中记录了上一次向目标节点发送心跳消息的时间 （ key
// 是节点 ID , value 是具体时间）。
type TimeoutDetector struct {
	mu          sync.Mutex // 保护所有
	maxDuration time.Duration
	// 从事件到时间的映射
	// 时间是事件的最后可见时间。
	records map[uint64]time.Time
}

// NewTimeoutDetector创建TimeoutDetector。
func NewTimeoutDetector(maxDuration time.Duration) *TimeoutDetector {
	return &TimeoutDetector{
		maxDuration: maxDuration,
		records:     make(map[uint64]time.Time),
	}
}

// 重置重置新的TimeOutDetector。
func (td *TimeoutDetector) Reset() {
	td.mu.Lock()
	defer td.mu.Unlock()

	td.records = make(map[uint64]time.Time)
}

// TimeoutDetector.observe（） 方法检测两次发送心跳消息的时间间隔
func (td *TimeoutDetector) Observe(which uint64) (bool, time.Duration) {
	td.mu.Lock()
	defer td.mu.Unlock()

	ok := true
	now := time.Now()	// 记录当前时间
	exceed := time.Duration(0)
	// 从 records 中获取上次向目标节点发送心跳消息的时间
	if pt, found := td.records[which]; found {
		exceed = now.Sub(pt) - td.maxDuration	// 计算两次心跳消息的时间间隔
		if exceed > 0 {
			ok = false
		}
	}
	td.records[which] = now	// 更新 records 中的对应记录
	return ok, exceed
}
